/**
 * 此示例演示了如何PuppeteerCrawler结合使用，使用 Headless Chrome / PuppeteerRequestQueue 递归地抓取Hacker News 网站。
 * 爬虫从单个 URL 开始，查找下一页的链接，将它们排入队列，然后继续，直到没有更多所需的链接可用。结果存储到默认数据集。在本地配置中，结果以 JSON 文件形式存储在./storage/datasets/default
 */
import { Dataset, PuppeteerCrawler, log as logg } from 'crawlee';

// 创建 PuppeteerCrawler 类的实例 - 爬虫
// 在无头 Chrome / Puppeteer 中自动加载 URL。
const crawler = new PuppeteerCrawler({
    // 您可以在此处设置传递给 launchPuppeteer() 函数的选项。
    launchContext: {
        launchOptions: {
            headless: true,
            // 其他 Puppeteer 选项
        },
    },

    // 几页后停止抓取
    maxRequestsPerCrawl: 50,

    // 每个要爬取的URL都会调用这个函数。
    // 这里可以编写你熟悉的Puppeteer脚本，
    // 例外的是浏览器和页面由 Crawlee 自动管理。
    // 该函数接受单个参数，该参数是具有以下字段的对象：
    // - request：Request 类的实例，包含 URL 和 HTTP 方法等信息
    // - page: Puppeteer 的 Page 对象（参见 https://pptr.dev/#show=api-class-page）
    async requestHandler({ request, page, enqueueLinks, log }) {
        log.info(`处理 ${request.url}...`);

        // 由 Puppeteer 在浏览器上下文中评估的函数。
        const data = await page.$$eval('.athing', ($posts: any[]) => {
            const scrapedData: { title: string; rank: string; href: string }[] = [];

            // 我们正在获取 Hacker News 上每个帖子的标题、排名和 URL。
            $posts.forEach(($post) => {
                scrapedData.push({
                    title: $post.querySelector('.title a').innerText,
                    rank: $post.querySelector('.rank').innerText,
                    href: $post.querySelector('.title a').href,
                });
            });

            return scrapedData;
        });

        // 将结果存储到默认数据集。
        await Dataset.pushData(data);

        // 找到下一页的链接，如果存在则将其加入队列。
        const infos = await enqueueLinks({
            selector: '.morelink',
        });

        if (infos.processedRequests.length === 0) log.info(`${request.url} is the last page!`);
    },

    // 如果页面处理失败超过 maxRequestRetries+1 次，则调用此函数。
    failedRequestHandler({ request, log }) {
        log.error(`请求 ${request.url} 失败次数过多。`);
    },
});

await crawler.addRequests(['https://news.ycombinator.com/']);

// 运行爬虫并等待其完成。
await crawler.run();

logg.debug('爬虫完成!');
